﻿using System;
using System.IO;
using System.Linq;
using System.Reflection;

namespace BuilderLibrary
{
    /// <summary>
    /// Class to get at external program paths. Just puts all of this in one place so
    /// crazy logic to locate things doesn't need to be here.
    /// </summary>
    public class ExternalToolLocations
    {

        /// <summary>
        /// Loads the default locations of all external tools.
        /// </summary>
        public static void LoadDefaultLocations()
        {
            CacheTemplateLoc();
            CacheWebViewer();
            CachePluginDirectories();
        }

        /// <summary>
        /// Returns the location of the viewer.
        /// </summary>
        public static string LocationWebViewer
        {
            get { CacheWebViewer(); return _viewer; }
            set { _viewer = value; }
        }

        /// <summary>
        /// Returns the Silver Light project files that we are going to use to build
        /// the final web site.
        /// </summary>
        public static string LocationSLTemplateControl
        {
            get
            {
                CacheTemplateLoc();
                return _templateLoc;
            }
            set { _templateLoc = value; }
        }

        /// <summary>
        /// Holds the internal location of the various files.
        /// </summary>
        private static string _templateLoc = null;

        /// <summary>
        /// Finds the location of the templates
        /// </summary>
        private static void CacheTemplateLoc()
        {
            if (_templateLoc != null)
            {
                return;
            }

            /// Development Code is BAD... but...
            _templateLoc = @"..\..\..\DeepTalkDisplay\bin\Debug";
            if (Directory.Exists(_templateLoc))
            {
                return;
            }

            /// Perhaps next to the current executable (from an install)?
            _templateLoc = GetAssemblyLocation() + "\\SLViewerTemplate";
            if (!Directory.Exists(_templateLoc))
            {
                throw new InvalidOperationException("Could not find the template files for the SilverLight control. Expected them in SLViewerTemplate");
            }
        }

        /// <summary>
        /// Location of the web viewer program.
        /// </summary>
        private static string _viewer = null;

        private static void CacheWebViewer()
        {
            if (_viewer != null)
            {
                return;
            }

            ///
            /// Development code is never good, but this makes it possible to actually use this!
            /// 

            if (IsLocalInstall)
            {
                DirectoryInfo baseDir = FindSubDirInTree("DeepTalkClientWebServer");
                FileInfo inf = new FileInfo(baseDir.FullName + @"\bin\Debug\DeepTalkClientWebServer.exe");
                if (!inf.Exists)
                {
                    throw new InvalidOperationException("Could not find the DeepTalkClientWebServer.exe program!");
                }
                _viewer = inf.FullName;
                return;
            }

            ///
            /// Ok -- had better hope it is in the right place then!
            /// 

            string assemblyLocation = GetAssemblyLocation();
            _viewer = assemblyLocation + "\\Web Viewer\\DeepTalkClientWebServer.exe";
        }

        /// <summary>
        /// Starting from the path name, walk back up until we find
        /// a directory with the appropriate subdirectory - return the dirinfo for that
        /// guy. Return null if we can't find that.
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        private static DirectoryInfo FindSubDirInTree(string subDirName)
        {
            var splitDirectories = new DirectoryInfo(".").FullName.Split(new char[] { Path.DirectorySeparatorChar });
            splitDirectories[0] = splitDirectories[0] + "\\";
            var alldirs = from i in Enumerable.Range(1, splitDirectories.Length)
                          select Path.Combine(splitDirectories.Take(i).ToArray());
            var foundDir = from d in alldirs
                           let loc = new DirectoryInfo(d + Path.DirectorySeparatorChar + subDirName)
                           where loc.Exists
                           select loc;
            return foundDir.FirstOrDefault();
        }

        /// <summary>
        /// Returns the location of the assembly that is calling - used to prime
        /// for various directories that we need to base things off. So it should get
        /// called only be the root assembly! :-)
        /// </summary>
        /// <returns></returns>
        private static string GetAssemblyLocation()
        {
            FileInfo binfo = new FileInfo(Assembly.GetCallingAssembly().Location);
            return binfo.DirectoryName;
        }

        /// <summary>
        /// development code in a final build is never good, however, this makes it possible
        /// to test it easily!
        /// </summary>
        private static bool IsLocalInstall
        {
            get
            {
                FileInfo inf = new FileInfo(@"..\..\..\DeepTalkClientWebServer\bin\Debug\DeepTalkClientWebServer.exe");
                return inf.Exists;
            }
        }

        /// <summary>
        /// The list of plugin directories that we can use
        /// </summary>
        public static DirectoryInfo[] RenderPluginSearchDirectories { get; private set; }

        /// <summary>
        /// Add the list of plug-in directories that we can access
        /// </summary>
        private static void CachePluginDirectories()
        {
            if (IsLocalInstall)
            {
                ///
                /// If we are doing development, then we only use the local plug-in directory
                /// 

                DirectoryInfo inf = new DirectoryInfo(@"..\..\..\LocalPlugins\Debug");
                RenderPluginSearchDirectories = new DirectoryInfo[] { inf };
            }
            else
            {
                ///
                /// Otherwise, we will use the following set of plugin directories
                /// 

                DirectoryInfo installed = new DirectoryInfo(GetAssemblyLocation() + "\\RenderPlugins");
                DirectoryInfo allUsers = new DirectoryInfo(System.Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData) + "\\DeepTalk Render Plugins");
                DirectoryInfo thisUserRoaming = new DirectoryInfo(System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData) + "\\DeepTalk Render Plugins");
                DirectoryInfo thisUserLocal = new DirectoryInfo(System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData) + "\\DeepTalk Render Plugins");

                RenderPluginSearchDirectories = new DirectoryInfo[]
                {
                    installed,
                    allUsers,
                    thisUserRoaming,
                    thisUserLocal
                };
            }
        }
    }
}
